
package client;

import common.SharedBuffer;
import common.packet.BodyState;
import common.packet.ClientInfo;
import common.packet.WorldState;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;

/**
 * Client physics thread. In its preStep() method it reads the contents of its
 * physicsInput SharedBuffer. If there's anything in there it updates the state
 * of the objects according to the contents of the given map. In its postStep()
 * method it writes the state of its objects into its physicsOutput SharedBuffer
 * which can later be read off it through the getPhysicsOutput method.
 *
 * @author xissburg
 */
public class PhysicsThreadC extends common.PhysicsThread
{
    private Game game;
    private SharedBuffer<WorldState> physicsInput;
    private SharedBuffer<Map<String, float[]>> physicsOutput;

    public PhysicsThreadC(Game game)
    {
        this.game = game;
        physicsInput = new SharedBuffer<WorldState>();
        physicsOutput = new SharedBuffer<Map<String, float[]>>();
    }

    public void setPhysicsInput(WorldState input) {
        physicsInput.set(input);
    }

    public Map<String, float[]> getPhysicsOutput(boolean wait) throws InterruptedException {
        return physicsOutput.get(wait);
    }

    @Override
    protected void preStep()
    {
        WorldState worldState = null;

        try {
            worldState = physicsInput.get(false);
        } catch (InterruptedException ex) {}

        if(worldState != null)
        {
            Collection<BodyState> bodyStates = worldState.getBodyStates();

            for(BodyState bs: bodyStates)
                physicsWorld.setBodyState(bs);

            //Extrapolate by latency/2
            physicsWorld.step(worldState.getLatency()*0.5f*(1e-3f));
        }
    }

    @Override
    protected void postStep()
    {
        Map<String, float[]> posMap = new HashMap<String, float[]>();
        Collection<ClientInfo> clients = game.getClients();

        Body b = physicsWorld.getBody("$ball");
        Vec2 pos = b.getWorldCenter();
        posMap.put("$ball", new float[]{pos.x, pos.y});

        for(ClientInfo ci: clients)
        {
            if(ci.getType() == ClientInfo.Type.SPECTATOR)
                continue;

            String name = ci.getName();
            b = physicsWorld.getBody(name);
            pos = b.getWorldCenter();
            posMap.put(name, new float[]{pos.x, pos.y});
        }

        physicsOutput.set(posMap);
    }
}
